import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.HashMap;

import com.exadel.flamingo.flex.messaging.amf.io.AMF3Deserializer;
import com.exadel.flamingo.flex.messaging.amf.io.AMF3Serializer;


public class ServiceThread extends Thread implements Runnable
{
	private AMFServer server;
	private Socket socket;
	private String input;
	
	
	
	// Construct
	ServiceThread(Socket socket)
	{
		this.server = AMFServer.getInstance();
		this.socket = socket;
	}

	public void run()
	{
		server.out("Connect <"+socket.getInetAddress().toString()+">");
		input = "";

		try {
			// Get input from the client
			InputStream is = socket.getInputStream();
			OutputStream os = socket.getOutputStream();
			AMF3InputStream ais = new AMF3InputStream(is);
			AMF3OutputStream aos = new AMF3OutputStream(os);
			
			
			
			HashMap request;
			
			//Class<?> service = Class.forName("AMFService");
			AMFService service = new AMFService();
			Object obj;
			while ((request = (HashMap) ais.readAMF3Object())!=null) {
				System.out.println(request.get("mode"));
					// invoke service
					Object params[]= (Object[]) request.get("params");
					Object result = invoke(service, (String)request.get("service"), params );
					
					// make response
					AMFResponse response = new AMFResponse();
					response.mode = AMFMode.RESPONSE;
					response.result = result;
					
					// write amf3
					aos.writeAMF3Object(response);
					aos.flush();
			}
			
			
			
		} catch (IOException ioe) {
			System.out.println("IOException on socket listen: " + ioe);
			ioe.printStackTrace();
		} catch (ClassNotFoundException cnfe) {
			// TODO
		}finally {
			try {
				server.out("Disonnect <"+socket.getInetAddress().toString()+">");
				this.finalize();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	

	  public static byte[] getBytes(Object obj) throws java.io.IOException{
	      ByteArrayOutputStream bos = new ByteArrayOutputStream();
	      ObjectOutputStream oos = new ObjectOutputStream(bos);
	      oos.writeObject(obj);
	      oos.flush();
	      oos.close();
	      bos.close();
	      byte [] data = bos.toByteArray();
	      return data;
	  }
	
	public Object invoke(Object obj, String methodName, Object[] objList) {
        Method[] methods = obj.getClass().getMethods();
       
        for(int i=0; i<methods.length; i++) {
                if(methods[i].getName().equals(methodName)) {
                        try {
                                if (methods[i].getReturnType().getName().equals("void")) {
                                        methods[i].invoke(obj, objList);       
                                } else {
                                        return methods[i].invoke(obj, objList);
                                }
                        } catch(IllegalAccessException lae) {
                                System.out.println("LAE : " + lae.getMessage());
                        } catch(InvocationTargetException ite) {
                                System.out.println("ITE : " + ite.getMessage());
                        }
                }
        }
        return null;
	}
	
	
	public void stopSocket()
	{
		try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
}
